package com.zmn.mcc.dubbo.impl.dept;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.dept.DeptBService;
import com.zmn.mcc.cache.DeptCache;
import com.zmn.mcc.common.constant.DeptConsts;
import com.zmn.mcc.common.dto.dept.BsDept;
import com.zmn.mcc.common.dto.dept.BsDeptDIO;
import com.zmn.mcc.common.dto.dept.BsDeptDRO;
import com.zmn.mcc.common.dto.dept.DeptDRO;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.mcc.dubbo.interfaces.dept.DeptListRemoteService;
import com.zmn.mcc.model.entity.dept.McDept;
import com.zmn.mcc.model.entity.dept.McDeptQuery;
import com.zmn.mcc.model.entity.staff.McStaff;
import com.zmn.mcc.services.interfaces.dept.DeptService;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import org.apache.dubbo.config.annotation.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanCopier;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author heguanghua
 * @since 2020/07/03 12:15
 */
@Service(version = DubboConsts.INTERFACE_VERSION, validation = "true")
public class DeptListRemoteServiceImpl implements DeptListRemoteService {
    private final Logger logger = LoggerFactory.getLogger(DeptListRemoteServiceImpl.class);

    private static final String TAG = "部门dubbo接口";

    @Resource
    private DeptBService deptBService;
    @Resource
    private DeptService deptService;
    @Resource
    private DeptCache deptCache;

    @Resource
    private StaffService staffService;


    @Override
    @ReadOnlyConnection
    public ResponseDTO<DeptDRO> getDept(Integer deptId) {

        if (NumberUtil.isNullOrZero(deptId)) {
            return ResponseDTO.fail("没有指定部门ID");
        }

        McDept dept = deptCache.getDept(deptId);

        if (Objects.isNull(dept)) {
            return ResponseDTO.fail("未查到指定数据");
        }

        // 对象转换
        BeanCopier copier = BeanCopier.create(McDept.class, DeptDRO.class, false);
        DeptDRO deptDRO = new DeptDRO();
        copier.copy(dept, deptDRO, null);

        logger.info(String.format("[%s]取得部门对象,dept:[%s]", TAG, JSONObject.toJSONString(dept)));
        return ResponseDTO.success(deptDRO, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<DeptDRO> getRootDept(Integer deptId) {

        if (NumberUtil.isNullOrZero(deptId)) {
            return ResponseDTO.fail("没有指定部门ID");
        }
        McDept dept = findParentDept(deptId);
        // 对象转换
        BeanCopier copier = BeanCopier.create(McDept.class, DeptDRO.class, false);
        DeptDRO deptDRO = new DeptDRO();
        copier.copy(dept, deptDRO, null);

        logger.info(String.format("[%s]取得部门对象,dept:[%s]", TAG, JSONObject.toJSONString(dept)));
        return ResponseDTO.success(deptDRO, "OK");
    }

    @Override
    public ResponseDTO<List<DeptDRO>> listDeptByIdAndKeyWord(Integer deptId, String keyWord) {

        if (NumberUtil.isNullOrZero(deptId)) {
            deptId = GlobalConsts.TOP_ID;
        }
        Integer finalDeptId = deptId;
        List<McDept> mcDepts = deptService.listValidDept();
        List<DeptDRO> deptDROS = BeanMapper.mapList(mcDepts, DeptDRO.class);
        // 定义出参结果集
        List<DeptDRO> result = new ArrayList<>(deptDROS.size());

        // 按照deptId递归构所有下级
        List<DeptDRO> deptDRO1 = buildDept(deptDROS, deptId);

        // 本级部门
//        DeptDRO deptDRO = Optional.ofNullable(deptDROS).orElse(Collections.emptyList())
//                .stream()
//                .filter(dept -> Objects.equals(dept.getDeptId(), finalDeptId))
//                .findFirst()
//                .orElse(null);
//        if (Objects.nonNull(deptDRO)) {
//            deptDRO1.add(deptDRO);
//        }

        // 按关键字赛选
        if (StringUtil.isNotBlank(keyWord)) {
            result = Optional.ofNullable(deptDRO1).orElse(Collections.emptyList())
                    .stream()
                    .filter(dept -> String.valueOf(dept.getDeptId()).contains(keyWord) || dept.getDeptName().contains(keyWord))
                    .collect(Collectors.toList());
        } else {
            result = deptDRO1;
        }

        return ResponseDTO.success(result);
    }

    /**
     * 寻找上级部门
     *
     * @param deptId
     * @return
     */
    private McDept findParentDept(Integer deptId) {
        McDept dept = deptCache.getDept(deptId);
        if (dept != null && !(dept.getParentId().equals(GlobalConsts.NO))) {
            dept = findParentDept(dept.getParentId());
        }
        return dept;
    }


    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listDeptByDeptIds(List<Integer> deptIds) {
        if (CollectionUtil.isNullOrEmpty(deptIds)) {
            return ResponseDTO.fail("deptIds不能为空");
        }

        McDeptQuery mcDeptQuery = new McDeptQuery();
        mcDeptQuery.setDeptIds(deptIds);
        List<McDept> depts = deptService.listByQuery(mcDeptQuery);

        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得部门对象列表,deptIds:[%s]", TAG, deptIds));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listDeptByLevelAndStatus(Integer level, Integer status) {
        // 如果level和status均为空，则查询所有部门

        McDeptQuery mcDeptQuery = new McDeptQuery();
        mcDeptQuery.setLevel(level);
        mcDeptQuery.setStatus(status);
        List<McDept> depts = deptService.listByQuery(mcDeptQuery);

        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得部门对象列表,level:[%s],status:[%s]", TAG, level, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listDeptVtByOrgId(Integer orgId, Integer status) {

        if (NumberUtil.isNullOrZero(orgId)) {
            return ResponseDTO.fail("没有指定组织架构ID");
        }

        List<McDept> depts = deptService.listByOrgId(orgId, status);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(depts);

        logger.info(String.format("[%s]取得部门Vt对象列表,orgId:[%s],status:[%s]", TAG, orgId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listDeptByOrgId(Integer orgId, Integer status) {

        if (NumberUtil.isNullOrZero(orgId)) {
            return ResponseDTO.fail("没有指定组织架构ID");
        }

        List<McDept> depts = deptService.listByOrgId(orgId, status);

        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得部门对象列表,orgId:[%s],status:[%s]", TAG, orgId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listDeptByOrgIds(List<Integer> orgIds, Integer status) {
        if (CollectionUtil.isNullOrEmpty(orgIds)) {
            return ResponseDTO.fail("没有指定组织架构IDS");
        }

        List<McDept> depts = deptService.listByOrgIds(orgIds, status);

        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得部门对象列表,orgIds:[%s],status:[%s]", TAG, orgIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listDeptVtByParentId(Integer parentId, Integer status) {

        if (NumberUtil.isNullOrZero(parentId)) {
            return ResponseDTO.fail("没有指定上级部门ID");
        }

        List<McDept> depts = deptService.listByParentId(null, parentId, status);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(depts);

        logger.info(String.format("[%s]取得下级部门Vt对象列表,parentId:[%s],status:[%s]", TAG, parentId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listDeptByParentId(Integer parentId, Integer status) {

        if (NumberUtil.isNullOrZero(parentId)) {
            return ResponseDTO.fail("没有指定上级部门ID");
        }

        List<McDept> depts = deptService.listByParentId(null, parentId, status);

        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得下级部门对象列表,parentId:[%s],status:[%s]", TAG, parentId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<List<DeptDRO>> listDeptByOrgIdAndParentIds(Integer orgId, List<Integer> parentIdList, Integer level, Integer status) {
//        if (NumberUtil.isNullOrZero(orgId) && CollectionUtil.isNullOrEmpty(parentIdList) && NumberUtil.isNullOrZero(level)) {
//            return ResponseDTO.fail("没有指定组织id或父节点id");
//        }
        List<McDept> depts = deptService.listDeptByOrgIdAndParentIds(orgId, parentIdList, level, status);
        // 对象转换
        List<DeptDRO> items = this.parseToDeptDRO(depts);

        logger.info(String.format("[%s]取得下级部门对象列表,orgId:[%s],parentIdList:[%s],level:[%s]", TAG, orgId, parentIdList.toString(), level));
        return ResponseDTO.success(items, "OK");
    }

    /**
     * 根据组织id列表、部门ID列表，查询部门ID列表下的所有子部门
     *
     * @param orgIds  组织id列表
     * @param deptIds 部门ID列表
     * @return 所有子部门id、名称、状态
     * @author xujie
     * @since 2021-05-17
     */
    @Override
    public ResponseDTO<List<VtDTO>> listSubDeptVtByOrgIdsAndDeptIds(List<Integer> orgIds, List<Integer> deptIds) {

        List<VtDTO> allSub = new ArrayList<>();
        for (; ; ) {
            List<VtDTO> subList = deptService.listSubDeptVtByOrgIdsAndDeptIds(orgIds, deptIds);
            if (subList == null || subList.size() == 0) {
                break;
            }
            allSub.addAll(subList);
            deptIds = subList.stream().map(VtDTO::getValue).collect(Collectors.toList());
        }
        return ResponseDTO.success(allSub, "OK");
    }

    @Override
    public ResponseDTO<List<BsDeptDRO>> listBsDeptByBsDeptId(List<Integer> bsDeptIds) {
        if (CollectionUtil.isNullOrEmpty(bsDeptIds)) {
            return ResponseDTO.fail("未指定北森部门ID");
        }

        // 查询部门信息
        List<McDept> depts = deptService.listByBsDeptId(bsDeptIds);
        if (CollectionUtil.isNullOrEmpty(depts)) {
            return ResponseDTO.success(new ArrayList<>(0), "OK");
        }

        // 组装返回数据
        List<BsDeptDRO> result = new ArrayList<>(depts.size());
        for (McDept dept : depts) {
            BsDeptDRO dro = new BsDeptDRO();
            BeanUtils.copyProperties(dept, dro);
            dro.setOperateType(DeptConsts.OPERATE_TYPE_SELECT);
            // 转换负责人
            if (Objects.nonNull(dept.getManagerId())) {
                McStaff manager = staffService.findByKey(dept.getManagerId());
                dro.setBsManagerId(Objects.nonNull(manager) ? manager.getBsUserId() : null);
            }
            // 转换直属领导
            if (Objects.nonNull(dept.getLeaderId())) {
                McStaff leader = staffService.findByKey(dept.getLeaderId());
                dro.setBsLeaderId(Objects.nonNull(leader) ? leader.getBsUserId() : null);
            }
            // 转换北森上级部门ID
            if (!Objects.equals(dept.getParentId(), GlobalConsts.TOP_ID)) {
                McDept parent = deptService.findByKey(dept.getParentId());
                dro.setBsParentId(parent.getBsDeptId());
            }
            result.add(dro);
        }

        return ResponseDTO.success(result, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<DeptDRO>> listValidZmnDept() {
        List<McDept> mcDepts = deptService.listValidZmnDept();
        return ResponseDTO.success(BeanMapper.mapList(mcDepts, DeptDRO.class));
    }

    @Override
    public ResponseDTO<String> saveBsDeptInfo(List<BsDeptDIO> list) {
        logger.info("[{}]同步北森部门数据开始：{}", TAG, list);

        // 参数校验
        if (CollectionUtil.isNullOrEmpty(list)) {
            logger.info("[{}]同步北森部门数据结束，同步的部门信息为空", TAG);
            return ResponseDTO.fail("同步的部门信息不能为空");
        }

        // 数据分类
        List<BsDeptDIO> waitInsertBsDept = list.stream().filter(e -> Objects.equals(e.getOperateType(), DeptConsts.OPERATE_TYPE_INSERT)).collect(Collectors.toList());
        List<BsDeptDIO> waitUpdateBsDept = list.stream().filter(e -> Objects.equals(e.getOperateType(), DeptConsts.OPERATE_TYPE_UPDATE)).collect(Collectors.toList());

        // 新增部门
        if (CollectionUtil.isNotNullOrEmpty(waitInsertBsDept)) {
            // 为了保证McDept的parentId有值，将部门数据转换成树，递归地新增
            List<BsDept> bsDeptList = buildBsDeptTree(waitInsertBsDept);
            recursionAdd(bsDeptList);
        }

        // 修改部门
        if (CollectionUtil.isNotNullOrEmpty(waitUpdateBsDept)) {
            List<BsDept> bsDeptList = buildBsDeptTree(waitUpdateBsDept);
            recursionUpdate(bsDeptList);
        }

        logger.info("[{}]同步北森部门数据结束", TAG);

        return ResponseDTO.success("OK");
    }

    private void recursionUpdate(List<BsDept> bsDeptList) {
        if (CollectionUtil.isNullOrEmpty(bsDeptList)) {
            return;
        }
        for (BsDept bsDept : bsDeptList) {
            if (!Objects.isNull(bsDept.getDeptId())) {
                McDept mcDept = deptService.findByKey(bsDept.getDeptId());
                if (Objects.isNull(mcDept)) {
                    continue;
                }
                mcDept.setBsDeptId(bsDept.getBsDeptId());
                mcDept.setDeptName(bsDept.getDeptName());
                mcDept.setStatus(bsDept.getStatus());
                // 转换直属领导
                if (Objects.nonNull(bsDept.getBsLeaderId())) {
                    McStaff leader = staffService.findByBsUserId(bsDept.getBsLeaderId());
                    mcDept.setLeaderId(Objects.nonNull(leader) ? leader.getStaffId() : null);
                } else {
                    mcDept.setLeaderId(null);
                }
                // 转换负责人
                if (Objects.nonNull(bsDept.getBsManagerId())) {
                    McStaff manager = staffService.findByBsUserId(bsDept.getBsManagerId());
                    mcDept.setManagerId(Objects.nonNull(manager) ? manager.getStaffId() : null);
                } else {
                    mcDept.setManagerId(null);
                }
                mcDept.setUpdateTime(DateUtil.getNow());
                // 保存信息
                ResponseDTO response = deptBService.modifyDept(mcDept);
                // 部门修改失败，子部门全部不修改
                if (!response.isSuccess()) {
                    logger.error("未能修改部门：{}，错误信息：{}", mcDept.getDeptName(), response.getMessage());
                    continue;
                }
            }
            // 递归的修改子部门
            recursionUpdate(bsDept.getChildren());
        }
    }

    /**
     * 递归的新增部门
     *
     * @param bsDeptList 北森部门
     */
    private void recursionAdd(List<BsDept> bsDeptList) {
        if (CollectionUtil.isNullOrEmpty(bsDeptList)) {
            return;
        }
        for (BsDept bsDept : bsDeptList) {
            if (!Objects.isNull(bsDept.getDeptName())) {
                McDept mcDept = new McDept();
                // 设置父部门ID
                if (Objects.isNull(bsDept.getBsParentId())) {
                    mcDept.setParentId(null);
                } else {
                    McDept mcParent = deptService.findByBsDeptId(bsDept.getBsParentId());
                    mcDept.setParentId(Objects.nonNull(mcParent) ? mcParent.getDeptId() : null);
                }
                mcDept.setBsDeptId(bsDept.getBsDeptId());
                mcDept.setDeptName(bsDept.getDeptName());
                mcDept.setOrgId(bsDept.getOrgId());
                // 转换直属领导
                if (Objects.nonNull(bsDept.getBsLeaderId())) {
                    McStaff leader = staffService.findByBsUserId(bsDept.getBsLeaderId());
                    mcDept.setLeaderId(Objects.nonNull(leader) ? leader.getStaffId() : null);
                }
                // 转换负责人
                if (Objects.nonNull(bsDept.getBsManagerId())) {
                    McStaff manager = staffService.findByBsUserId(bsDept.getBsManagerId());
                    mcDept.setManagerId(Objects.nonNull(manager) ? manager.getStaffId() : null);
                }
                mcDept.setUpdater("北森同步");
                // 保存部门
                ResponseDTO response = deptBService.addDept(mcDept);
                // 部门新增失败，子部门全部不添加
                if (!response.isSuccess()) {
                    logger.error("未能新增部门：{}，错误信息：{}", mcDept.getDeptName(), response.getMessage());
                    continue;
                }
            }
            // 递归的新增下级部门
            recursionAdd(bsDept.getChildren());
        }
    }

    /**
     * 构建北森部门树
     *
     * @param deptList 北森部门列表
     * @return
     */
    private List<BsDept> buildBsDeptTree(List<BsDeptDIO> deptList) {
        // 检查列表为空
        if (CollectionUtil.isNullOrEmpty(deptList)) {
            return new ArrayList<>(0);
        }

        // 依次处理部门
        int size = deptList.size();
        List<BsDept> rootList = new ArrayList<>(size);
        Map<Integer, BsDept> deptMap = new HashMap<>(size);
        for (BsDeptDIO dio : deptList) {
            // 赋值部门对象
            Integer deptId = dio.getBsDeptId();
            BsDept dept = deptMap.get(deptId);
            if (Objects.isNull(dept)) {
                dept = new BsDept();
                dept.setChildren(new ArrayList<>());
                deptMap.put(deptId, dept);
            }
            BeanUtils.copyProperties(dio, dept, "children");

            // 根据父标识处理
            Integer parentId = dio.getBsParentId();
            if (Objects.nonNull(parentId)) {
                // 构建父部门对象
                BsDept parent = deptMap.get(parentId);
                if (Objects.isNull(parent)) {
                    parent = new BsDept();
                    parent.setBsDeptId(parentId);
                    parent.setChildren(new ArrayList<>());
                    deptMap.put(parentId, parent);
                    // 添加上级部门对象，解决上级部门出现在下级部门后面的问题
                    BsDept temp = parent;
                    if (deptList.stream().noneMatch(item -> Objects.equals(item.getBsDeptId(), temp.getBsDeptId()))) {
                        rootList.add(parent);
                    }
                }

                // 添加子部门对象
                parent.getChildren().add(dept);
            } else {
                // 添加根部门对象
                rootList.add(dept);
            }
        }

        // 返回根部门对象
        return rootList;
    }


    /**
     * 把原始的部门对象McDept转换为VtDTO对象
     *
     * @param depts
     * @return List<DeptDRO>
     */
    private List<VtDTO> parseToVtDTO(List<McDept> depts) {

        List<VtDTO> items = new ArrayList<>();

        for (McDept dept : depts) {
            items.add(new VtDTO(dept.getDeptId(), dept.getDeptName()));
        }
        return items;
    }

    /**
     * 把原始的部门对象McDept转换为Dubbo出参对象
     *
     * @param depts
     * @return List<DeptDRO>
     */
    private List<DeptDRO> parseToDeptDRO(List<McDept> depts) {

        List<DeptDRO> items = new ArrayList<>();

        // 对象转换
        BeanCopier copier = BeanCopier.create(McDept.class, DeptDRO.class, false);
        for (McDept dept : depts) {
            DeptDRO deptDRO = new DeptDRO();
            copier.copy(dept, deptDRO, null);
            items.add(deptDRO);
        }
        return items;
    }

    /**
     * 描述: 递归构建部门下级
     *
     * @param deptList 部门列表
     * @param deptId   需要递归查询部门id
     * @return List<com.zmn.mcc.model.entity.dept.McDept>
     * @author guoqiao
     * @since 2021/5/20 19:02
     */
    private List<DeptDRO> buildDept(List<DeptDRO> deptList, int deptId) {
        List<DeptDRO> treeList = new ArrayList<>(deptList.size());
        for (DeptDRO dept : deptList) {
            if (dept.getParentId() == deptId) {
                treeList.add(dept);
                for (DeptDRO deptDRO : buildDept(deptList, dept.getDeptId())) {
                    treeList.add(deptDRO);
                }
            }
        }
        return treeList;
    }
}
